package meow

import meow.Utils
import org.grails.plugins.imagetools.ImageTool

/**
 * User controller.
 */
class AccountController {

  def authenticateService

  // the delete, save and update actions only accept POST requests
  static Map allowedMethods = [delete: 'POST', save: 'POST', update: 'POST']

  def index = {
    redirect action: list, params: params
  }

  def list = {
    if (!params.max) {
      params.max = Utils.MAX_RESULT
    }
    [accountList: Account.list(params)]
  }

  def show = {
    def account = Account.get(params.id)
    if (!account) {
      flash.message = "Account not found with id $params.id"
      redirect action: list
      return
    }
    List roleNames = []
    for (role in account.authorities) {
      roleNames << role.authority
    }
    roleNames.sort {n1, n2 ->
      n1 <=> n2
    }
    [account: account, roleNames: roleNames]
  }

  def edit = {
    def account = Account.findByUsername(principalInfo.username)
    buildAccountModel(account)
  }

  /**
   * Account update action.
   */
  def update = {

    def account = Account.get(params.id)
    if (!account) {
      flash.message = "Account not found with id $params.id"
      redirect action: edit, id: params.id
      return
    }

    long version = params.version.toLong()
    if (account.version > version) {
      account.errors.rejectValue 'version', "account.optimistic.locking.failure",
                                 "Another user has updated this Account while you were editing."
      render view: 'edit', model: buildAccountModel(account)
      return
    }

    def oldPassword = account.passwd
    account.properties = params
    if (!params.passwd.equals(oldPassword)) {
      account.passwd = authenticateService.encodePassword(params.passwd)
    }
    if (account.save(flush:true)) {
      flash.message = "ユーザ情報を更新しました。"
      redirect action: show, id: account.id
    }
    else {
      render view: 'edit', model: buildAccountModel(account)
    }
  }

  private Map buildAccountModel(account) {

    List roles = Authority.list()
    roles.sort {r1, r2 ->
      r1.authority <=> r2.authority
    }
    Set userRoleNames = []
    for (role in account.authorities) {
      userRoleNames << role.authority
    }
    LinkedHashMap<Authority, Boolean> roleMap = [:]
    for (role in roles) {
      roleMap[(role)] = userRoleNames.contains(role.authority)
    }

    return [account: account, roleMap: roleMap]
  }

  /** アイコン変更画面へ     */
  def icon = {
    [account: Account.findByUsername(principalInfo.username)]
  }

  // --- ここまでは acegiプラグインが自動生成したコードをベースにしてる。
  // --- なんかテキトウ感があるのもacegiプラグインのせい。:-)

  /** アイコン登録     */
  def upload = {
    // 後勝ち＆非トランザクション処理で十分ざんす
    def icon = request.getFile('icon')
    if (icon.empty) {
      flash.message = "アップロードしたファイルは空です。"
      redirect action: 'icon'
      return
    }
    if (!(icon.fileItem =~ /.*\.(png|jpg|gif)/)) {
      flash.message = ".jpg/.png/.gif以外のファイルは未対応です。"
      redirect action: 'icon'
      return
    }

    // アイコンファイルを永続化
    def avatorIcon = AvatorIcon.findByUsername(principalInfo.username)
    if (!avatorIcon)
      avatorIcon = new AvatorIcon(username: principalInfo.username)

    def imageTool = new ImageTool()
    imageTool.load(icon.bytes)

    // 大きいアイコン(64x64)
    imageTool.thumbnail(64)
    avatorIcon.largeIcon = imageTool.getBytes("PNG")

    // 小さいアイコン(32x32)
    imageTool.thumbnail(32)
    avatorIcon.smallIcon = imageTool.getBytes("PNG")

    avatorIcon.save()

    flash.message = "素敵なアイコンですね。"
    redirect action: 'icon'
  }

  /** お気に入りリスト     */
  def friends = {
    if (!params.max) params.max = Utils.MAX_RESULT
    if (!params.offset) params.offset = 0
    Followers.friendsList(params.username,
                          params.offset.toInteger())
  }

  /** お気に入られリスト     */
  def followers = {
    if (!params.offset) params.offset = 0
    Followers.followersList(params.username,
                            params.offset.toInteger())
  }

}
